package client;

import java.io.*;
import java.net.*;
import java.util.Date;
import model.Flights;
import model.Routes;
import model.Points;
import model.ProcessXMLData;
import model.DataLoadable;
import model.Flight;

/**
 * Класс, реализующий обращение к серверу
 * @version 1.0
 */
public class IOCLient {

	public static final String serverId = "localhost";

    /**
     * Метод сохраняет объект на сервер
     * @param fileName Имя файла
     * @param data Объект
     * @param overwrite Приоритет при обновлении объектов
     */
    public static void saveDataToServer(String filename, DataLoadable data, boolean overwtite, String nameId) {
        Socket socket;
        ObjectOutputStream sOut;

        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);
            sOut.writeObject(nameId);
            sOut.flush();
            if (data.getClass().equals(Flights.class)) {
                sOut.writeObject("SaveFlights");
            }
            if (data.getClass().equals(Routes.class)) {
                sOut.writeObject("SaveRoutes");
            }
            if (data.getClass().equals(Points.class)) {
                sOut.writeObject("SavePoints");
            }
            sOut.flush();
            sOut.writeObject(filename);
            sOut.flush();
            sOut.writeBoolean(overwtite);
            sOut.flush();
            sOut.writeObject(ProcessXMLData.saveDataToXML(data));
            sOut.flush();
            bOut.close();
            sOut.close();
            socket.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Метод загружает объект сервера
     * @param fileName Имя файла
     * @param c Класс загружаемого объекта
     * @return DataLoadable Объект
     */
    public static DataLoadable loadDataFromServer(String filename, Class c, String nameId) {
        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);
            sOut.writeObject(nameId);
            sOut.flush();
            if (c.getName().equals("model.Flights")) {
                sOut.writeObject("LoadFlights");
            }
            if (c.getName().equals("model.Routes")) {
                sOut.writeObject("LoadRoutes");
            }
            if (c.getName().equals("model.Points")) {
                sOut.writeObject("LoadPoints");
            }
            sOut.flush();
            sOut.writeObject(filename);
            sOut.flush();
            bOut.flush();

            BufferedInputStream bIn = new BufferedInputStream(socket.getInputStream());
            sIn = new ObjectInputStream(bIn);
            DataLoadable data = ProcessXMLData.loadDataFromXML((String) sIn.readObject(), c);
            bOut.close();
            sIn.close();
            socket.close();
            return data;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Добавление или редактирование полета
     * @param flight обрабатываемый полет
     * @param command вид команды
     * @param nameId имя клиента
     * @return Flights все полеты
     */
    public static Flights work(Flight flight, String command, String nameId) {

        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);

            sOut.writeObject(nameId);
            sOut.flush();

            sOut.writeObject(command);
            sOut.flush();
            flight.getRoute().id = 1;
            flight.getRoute().getPointArrive().id = 2;
            flight.getRoute().getPointDepart().id = 3;
            sOut.writeObject(flight);
            sOut.flush();

            BufferedInputStream gsIn = new BufferedInputStream(socket.getInputStream());
            sIn = new ObjectInputStream(gsIn);
            Flights flights = (Flights) sIn.readObject();
            gsIn.close();
            sIn.close();
            bOut.close();
            sOut.close();
            socket.close();
            return flights;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Удаление полета
     * @param number номер удаляемого полета
     * @param nameId имя клиента
     * @return Flights все полеты
     */
    public static Flights delete(int number, String nameId) {
        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);
            sOut.writeObject(nameId);
            sOut.flush();
            sOut.writeObject("delete");
            sOut.flush();
            sOut.writeInt(number);
            sOut.flush();
            BufferedInputStream bIn = new BufferedInputStream(socket.getInputStream());
            sIn = new ObjectInputStream(bIn);
            Flights flights = (Flights) sIn.readObject();
            bOut.flush();
            sOut.flush();
            bIn.close();
            sIn.close();
            bOut.close();
            sOut.close();
            socket.close();
            return flights;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Поиск полета по его полям
     * @param flightsNumber Номер рейса
     * @param aircraft Название аэробуса
     * @param arriveTown Город прибытия
     * @param arriveAirport Аэропорт прибытия
     * @param departTown Город отправления
     * @param departArport Аэропорт отправления
     * @param departTime Время вылета
     * @param nameId имя клиента
     * @return Flights все полеты
     */
    public static Flights search(int flightsNumber, String aircraft,
            String arriveTown, String arriveAirport,
            String departTown, String departArport, Date departTime, String nameId) {
        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);

            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
            ObjectOutputStream oos = new ObjectOutputStream(bos);
//TODO Name of client
            oos.writeObject(nameId);
            oos.flush();
            bos.flush();

            oos.writeObject("search");
            oos.flush();
            bos.flush();

            oos.writeInt(flightsNumber);
            oos.flush();
            bos.flush();

            oos.writeObject(aircraft);
            oos.flush();

            oos.writeObject(arriveTown);
            oos.flush();

            oos.writeObject(arriveAirport);
            oos.flush();

            oos.writeObject(departTown);
            oos.flush();

            oos.writeObject(departArport);
            oos.flush();

            oos.writeObject(departTime);
            oos.flush();

            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Flights flights = (Flights) ois.readObject();
            ois.close();
            bis.close();
            bos.close();
            oos.close();
            socket.close();
            return flights;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Обновление данных
     * @param nameId имя клиента
     * @return Flights все полеты
     */
    public static Flights reload(String nameId) {

        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);

            sOut.writeObject(nameId);
            sOut.flush();

            sOut.writeObject("reload");
            sOut.flush();

            BufferedInputStream gsIn = new BufferedInputStream(socket.getInputStream());
            sIn = new ObjectInputStream(gsIn);
            Flights flights = (Flights) sIn.readObject();
            gsIn.close();
            sIn.close();
            bOut.close();
            sOut.close();
            socket.close();
            return flights;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
  /**
     * Отключение клиента
     * @param nameId имя клиента
     */
    public static void exit(String nameId) {

        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);

            sOut.writeObject(nameId);
            sOut.flush();

            sOut.writeObject("exit");
            sOut.flush();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

        public static void open(String nameId) {

        Socket socket;
        ObjectInputStream sIn;
        ObjectOutputStream sOut;
        try {
            socket = new Socket(serverId, 12371);
            BufferedOutputStream bOut = new BufferedOutputStream(socket.getOutputStream());
            sOut = new ObjectOutputStream(bOut);

            sOut.writeObject(nameId);
            sOut.flush();

            sOut.writeObject("open");
            sOut.flush();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
